skins_collectible = {}

local storage = minetest.get_mod_storage()
local players_skins = {}                        -- KEY: p_name; VALUE: {skins_ID}
local loaded_skins = {}
local equipped_skin = {}                        -- KEY: p_name; VALUE: skin ID



local function load_skins()

  local locations_dir = minetest.get_modpath("skins_collectible") .. "/skins_data"
  local locations_content = minetest.get_dir_list(locations_dir)

  for _, file_name in pairs(locations_content) do

    local file = io.open(locations_dir .. "/" .. file_name, "r")
    local data = string.split(file:read("*all"), "\n")

    file:close()

    local skin_ID           = string.match(file_name, "(%d+)_")
    local skin_name         = data[1]
    local skin_description  = data[2]
    local skin_hint         = data[3]
    local skin_model        = data[4]
    local skin_texture      = data[5]
    local skin_tier         = tonumber(data[6])
    local skin_img          = data[7]
    local skin_author       = data[8]

    if data[7] and data[7] == "-1" then
      skin_img = "blank.png"
    end

    loaded_skins[tonumber(skin_ID)] = {
      name        = skin_name,
      description = skin_description,
      hint        = skin_hint,
      model       = skin_model,
      texture     = skin_texture,
      tier        = skin_tier,
      img         = skin_img,
      author      = skin_author,
    }

  end
end

load_skins()




----------------------------------------------
-------------------CORPO----------------------
----------------------------------------------

function skins_collectible.load_player_data(player)

  local p_name = player:get_player_name()

  -- se il giocatore entra per la prima volta, lo inizializzo...
  if storage:get_string(p_name) == "" then

    local default_skins = minetest.deserialize(minetest.settings:get("skinsc_default_skins"))

    players_skins[p_name] = {}

    -- sblocco le skin base
    for _, ID in pairs(default_skins) do
      players_skins[p_name][ID] = true
    end

    storage:set_string(p_name, minetest.serialize(players_skins[p_name]))

    -- ...e gli assegno una skin randomica
    local random_ID = math.random(6)
    skins_collectible.set_skin(player, random_ID, true)

  --sennò gli assegno la skin che aveva
  else
    local skin_ID = player:get_meta():get_int("skins_collectible:skin_ID")

    players_skins[p_name] = minetest.deserialize(storage:get_string(p_name))
    skins_collectible.set_skin(player, skin_ID)
  end
end



function skins_collectible.unlock_skin(p_name, skin_ID)

  -- se la skin non esiste, annullo
  if not loaded_skins[skin_ID] then
    local error = "[SKINS_COLLECTIBLE] There has been an attempt to give player " .. p_name .. " a skin that doesn't exist (ID = " .. skin_ID .. ")!"
    minetest.log("warning", error)
    return false, error end

  -- se il giocatore non si è mai connesso, annullo
  if storage:get_string(p_name) == "" then
    local error = "[SKINS COLLECTIBLE] Player " .. p_name .. " is not in the skin database (meaning the player has never connected)"
    minetest.log("warning", error)
    return false, error end

  -- se ce l'ha già, annullo
  if skins_collectible.is_skin_unlocked(p_name, skin_ID) then
    return end

  local p_skins

  -- se è online
  if minetest.get_player_by_name(p_name) then
    p_skins = players_skins[p_name]
    minetest.chat_send_player(p_name, "You've unlocked the skin " .. loaded_skins[skin_ID].name .. "!")
  -- se è offline
  else
    p_skins = minetest.deserialize(storage:get_string(p_name))
  end

  p_skins[skin_ID] = true
  storage:set_string(p_name, minetest.serialize(p_skins))
end



function skins_collectible.remove_skin(p_name, skin_ID)

  -- se la skin non esiste, annullo
  if not loaded_skins[skin_ID] then
    local error = "[SKINS_COLLECTIBLE] There has been an attempt to remove player " .. p_name .. " a skin that doesn't exist (ID = " .. skin_ID .. ")!"
    minetest.log("warning", error)
    return false, error end

  -- se il giocatore non si è mai connesso, annullo
  if storage:get_string(p_name) == "" then
    local error = "[SKINS COLLECTIBLE] Player " .. p_name .. " is not in the skin database (meaning the player has never connected)"
    minetest.log("warning", error)
    return false, error end

  -- se già gli manca, annullo
  if not skins_collectible.is_skin_unlocked(p_name, skin_ID) then
    return end

  local p_skins

  -- se è online
  if minetest.get_player_by_name(p_name) then
    p_skins = players_skins[p_name]
    minetest.chat_send_player(p_name, "Your skin " .. loaded_skins[skin_ID].name .. " has been removed...")
  -- se è offline
  else
    p_skins = minetest.deserialize(storage:get_string(p_name))
  end

  -- rimuovo
  p_skins[skin_ID] = false
  storage:set_string(p_name, minetest.serialize(p_skins))
end





----------------------------------------------
--------------------UTILS---------------------
----------------------------------------------

function skins_collectible.is_skin_unlocked(p_name, skin_ID)

  -- per controllare anche giocatori offline
  local p_skins = not players_skins[p_name] and minetest.deserialize(storage:get_string(p_name)) or players_skins[p_name]

  if p_skins and p_skins[skin_ID] then return true
  else return false end
end





----------------------------------------------
-----------------GETTERS----------------------
----------------------------------------------

function skins_collectible.get_preview(skin_ID)
  return string.match(loaded_skins[skin_ID].texture, "(.*)%.png") .. "_preview.png"
end



function skins_collectible.get_skin(skin_ID)
  return loaded_skins[skin_ID]
end



function skins_collectible.get_player_skin(p_name)
  return loaded_skins[equipped_skin[p_name]]
end



function skins_collectible.get_player_skin_ID(p_name)
  return equipped_skin[p_name]
end




function skins_collectible.get_loaded_skins_amount()
  return #loaded_skins
end





----------------------------------------------
-----------------SETTERS----------------------
----------------------------------------------

function skins_collectible.set_skin(player, skin_ID, is_permanent)
  player_api.set_texture(player, loaded_skins[skin_ID].texture)

  local p_name = player:get_player_name()

  equipped_skin[p_name] = skin_ID

  if is_permanent then
    player:get_meta():set_int("skins_collectible:skin_ID", skin_ID)
  end

  -- eventuali callback
  for _, callback in ipairs(skins_collectible.registered_on_set_skin) do
    callback(player:get_player_name(), skin_ID)
  end
end
